{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 3, Topic 1: Large Hamming Weight Swings (MAIN)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**SUMMARY:** *In the previous part of the course, you saw that a microcontroller's power consumption changes based on what it's doing. In the case of a simple password check, this allowed us to see how many characters of the password we had correct, eventually resulting in the password being broken.*\n",
    "\n",
    "*That attack was based on different code execution paths showing up differently in power traces. In this next set of labs, we'll posit that, not only does different instructions affect power consumption, the data being manipulated in the microcontroller also affects power consumption.*\n",
    "\n",
    "\n",
    "**LEARNING OUTCOMES:**\n",
    "\n",
    "* Using a power measurement to 'validate' a possible device model.\n",
    "* Detecting the value of a single bit using power measurement.\n",
    "* Breaking AES using the classic DPA attack."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prerequisites\n",
    "\n",
    "Hold up! Before you continue, check you've done the following tutorials:\n",
    "\n",
    "* ☑ Jupyter Notebook Intro (you should be OK with plotting & running blocks).\n",
    "* ☑ SCA101 Intro (you should have an idea of how to get hardware-specific versions running).\n",
    "* ☑ SCA101 Part 2 (you should understand how power consupmtion changes based on what code is being run)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Power Trace Gathering\n",
    "\n",
    "At this point you've got to insert code to perform the power trace capture. There are two options here:\n",
    "* Capture from physical device.\n",
    "* Read from a file.\n",
    "\n",
    "You get to choose your adventure - see the two notebooks with the same name of this, but called `(SIMULATED)` or `(HARDWARE)` to continue. Inside those notebooks you should get some code to copy into the following section, which will define the capture function.\n",
    "\n",
    "Be sure you get the `\"✔️ OK to continue!\"` print once you run the next cell, otherwise things will fail later on!\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CWHUSKY'\n",
    "CRYPTO_TARGET = 'TINYAES128C'\n",
    "VERSION = 'HARDWARE'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if VERSION == 'HARDWARE':\n",
    "    %run \"Lab 3_1 - Large Hamming Weight Swings (HARDWARE).ipynb\"\n",
    "elif VERSION == 'SIMULATED':\n",
    "    %run \"Lab 3_1 - Large Hamming Weight Swings (SIMULATED).ipynb\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(len(trace_array))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert len(trace_array) == 100\n",
    "print(\"✔️ OK to continue!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Grouping Traces\n",
    "\n",
    "As we've seen in the slides, we've made an assumption that setting bits on the data lines consumes a measurable amount of power. Now, we're going test that theory by getting our target to manipulate data with a very high Hamming weight (0xFF) and a very low Hamming weight (0x00). For this purpose, the target is currently running AES, and it encrypted the text we sent it. If we're correct in our assumption, we should see a measurable difference between power traces with a high Hamming weight and a low one.\n",
    "\n",
    "Currently, these traces are all mixed up. Separate them into two groups: `one_list` and `zero_list`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ###################\n",
    "# Add your code here\n",
    "# ###################\n",
    "#raise NotImplementedError(\"Add Your Code Here\")\n",
    "\n",
    "# ###################\n",
    "# START SOLUTION\n",
    "# ###################\n",
    "one_list = []\n",
    "zero_list = []\n",
    "\n",
    "for i in range(len(trace_array)):\n",
    "    if textin_array[i][0] == 0x00:\n",
    "        zero_list.append(trace_array[i])\n",
    "    else:\n",
    "        one_list.append(trace_array[i])\n",
    "# ###################\n",
    "# END SOLUTION\n",
    "# ###################\n",
    "\n",
    "assert len(one_list) > len(zero_list)/2\n",
    "assert len(zero_list) > len(one_list)/2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We should have two different lists. Whether we sent 0xFF or 0x00 was random, so these lists likely won't be evenly dispersed. Next, we'll want to take an average of each group (make sure you take an average of each trace at each point! We don't want an average of the traces in time), which will help smooth out any outliers and also fix our issue of having a different number of traces for each group:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ###################\n",
    "# Add your code here\n",
    "# ###################\n",
    "#raise NotImplementedError(\"Add Your Code Here\")\n",
    "\n",
    "# ###################\n",
    "# START SOLUTION\n",
    "# ###################\n",
    "import numpy as np\n",
    "one_avg = np.mean(one_list, axis=0)\n",
    "zero_avg = np.mean(zero_list, axis=0)\n",
    "# ###################\n",
    "# END SOLUTION\n",
    "# ###################"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, subtract the two averages and plot the resulting data:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ###################\n",
    "# Add your code here\n",
    "# ###################\n",
    "#raise NotImplementedError(\"Add Your Code Here\")\n",
    "\n",
    "# ###################\n",
    "# START SOLUTION\n",
    "# ###################\n",
    "diff = one_avg - zero-avg\n",
    "cw.plot(diff)\n",
    "# ###################\n",
    "# END SOLUTION\n",
    "# ###################"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should see a very distinct trace near the beginning of the plot, meaning that the data being manipulated in the target device is visible in its power trace! Again, there's a lot of room to explore here:\n",
    "\n",
    "* Try setting multiple bytes to 0x00 and 0xFF.\n",
    "* Try using smaller hamming weight differences. Is the spike still distinct? What about if you capture more traces?\n",
    "* We focused on the first byte here. Try putting the difference plots for multiple different bytes on the same plot.\n",
    "* The target is running AES here. Can you get the spikes to appear in different places if you set a byte in a later round of AES (say round 5) to 0x00 or 0xFF?\n",
    "\n",
    "One other note that might trip you out: rememeber you are measuring the voltage at the input to ChipWhisperer, which is measured across a shunt resistor. The end result of this is that a lower voltage actually means more power. So you might see the spikes flipped from the \"expected\" direction based on a 1 taking more power than a 0."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "<small>NO-FUN DISCLAIMER: This material is Copyright (C) NewAE Technology Inc., 2015-2020. ChipWhisperer is a trademark of NewAE Technology Inc., claimed in all jurisdictions, and registered in at least the United States of America, European Union, and Peoples Republic of China.\n",
    "\n",
    "Tutorials derived from our open-source work must be released under the associated open-source license, and notice of the source must be *clearly displayed*. Only original copyright holders may license or authorize other distribution - while NewAE Technology Inc. holds the copyright for many tutorials, the github repository includes community contributions which we cannot license under special terms and **must** be maintained as an open-source release. Please contact us for special permissions (where possible).\n",
    "\n",
    "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</small>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
